﻿"""
System configuration router used to manage administrator settings.
"""
from datetime import datetime, timedelta
from fastapi import APIRouter, Depends, HTTPException, Request, status
from sqlalchemy.orm import Session

from app.database import get_db
from app.schemas.system_config import (
    AdminPasswordVerify,
    AdminPasswordUpdate,
)
from app.services import system_config_service
from app.routers.auth import get_current_admin_user
from app.models.user import User

router = APIRouter()

# Basic in-memory rate limiting for administrator password verification attempts
_FAILED_ATTEMPTS: dict[str, dict[str, object]] = {}
MAX_FAILED_ATTEMPTS = 5
BLOCK_DURATION = timedelta(minutes=10)


def _client_key(request: Request) -> str:
    """Return a deterministic key for identifying the requesting client."""
    if request.client and request.client.host:
        return request.client.host
    return "anonymous"


def _ensure_not_blocked(client_key: str) -> None:
    """Raise if the client is currently blocked due to repeated failures."""
    record = _FAILED_ATTEMPTS.get(client_key)
    if not record:
        return

    blocked_until = record.get("blocked_until")
    if not blocked_until:
        return

    now = datetime.utcnow()
    if blocked_until > now:
        retry_after = int((blocked_until - now).total_seconds())
        raise HTTPException(
            status_code=status.HTTP_429_TOO_MANY_REQUESTS,
            detail="Too many failed attempts. Try again later.",
            headers={"Retry-After": str(retry_after)},
        )

    # Ban expired -> reset state
    _FAILED_ATTEMPTS.pop(client_key, None)


def _register_failure(client_key: str) -> None:
    """Record a failed attempt and block client when threshold is exceeded."""
    now = datetime.utcnow()
    record = _FAILED_ATTEMPTS.setdefault(client_key, {"count": 0, "blocked_until": None})
    record["count"] = int(record.get("count", 0)) + 1

    if record["count"] >= MAX_FAILED_ATTEMPTS:
        record["blocked_until"] = now + BLOCK_DURATION
        record["count"] = 0
        retry_after = int(BLOCK_DURATION.total_seconds())
        raise HTTPException(
            status_code=status.HTTP_429_TOO_MANY_REQUESTS,
            detail="Too many failed attempts. Try again later.",
            headers={"Retry-After": str(retry_after)},
        )

    _FAILED_ATTEMPTS[client_key] = record


def _reset_attempts(client_key: str) -> None:
    """Clear any stored failure counters for the client."""
    _FAILED_ATTEMPTS.pop(client_key, None)


@router.post("/admin-password/verify")
def verify_admin_password(
    data: AdminPasswordVerify,
    request: Request,
    db: Session = Depends(get_db)
):
    """Verify administrator password with simple brute-force protection."""
    client_key = _client_key(request)
    _ensure_not_blocked(client_key)

    is_valid = system_config_service.verify_admin_password(db, data.password)

    if is_valid:
        _reset_attempts(client_key)
        return {"valid": True, "message": "Password verified successfully"}

    try:
        _register_failure(client_key)
    except HTTPException:
        raise

    return {"valid": False, "message": "Invalid administrator password"}


@router.put("/admin-password")
def update_admin_password(
    data: AdminPasswordUpdate,
    db: Session = Depends(get_db),
    current_admin: User = Depends(get_current_admin_user)
):
    """Update administrator password (admin only)."""
    success = system_config_service.update_admin_password(
        db,
        data.old_password,
        data.new_password
    )

    if success:
        return {"message": "Administrator password updated successfully"}
    return {"message": "Failed to update administrator password"}
